package com.mdp.dev.dao;

import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
import com.mdp.core.SpringContextUtils;
import com.mdp.core.entity.LangTips;
import com.mdp.core.err.BizException;
import com.mdp.core.utils.JdbcUtils;
import com.mdp.core.utils.ObjectTools;
import com.mdp.dev.entity.FieldInfo;
import com.mdp.dev.utils.DateUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.util.StringUtils;

import javax.sql.DataSource;
import java.sql.*;
import java.util.Date;
import java.util.*;


/**
 * 
 * @author cyc 将entity的名字改成符合驼峰命名规范的名字 20150215
 * @see org.springframework.jdbc.support.JdbcUtils
 *
 */
@Repository
public class CodeGenDao implements InitializingBean{

	
	@Autowired
	GenDataDao genDataDao;

	DynamicRoutingDataSource dataSourceService;

	
	public Logger logger = LoggerFactory.getLogger(CodeGenDao.class);

	public Connection getConnection() {
		try {
			if(dataSourceService==null){
				dataSourceService=SpringContextUtils.getBean(DynamicRoutingDataSource.class);
			}
			return dataSourceService.getConnection();
		} catch (SQLException e) {
			logger.error("db-connection-error",e);
			throw new RuntimeException("db-connection-error",e);
		}
	}
	public Connection getConnection(String ds) {
		try {
			if(ObjectTools.isEmpty(ds)){
				throw new BizException(LangTips.errMsg("ds-required","数据源%s不能为空","ds"));
			}
			if(dataSourceService==null){
				dataSourceService=SpringContextUtils.getBean(DynamicRoutingDataSource.class);
			}
			DataSource dataSource=dataSourceService.getDataSource(ds);
			if(dataSource==null){
				throw new BizException(LangTips.errMsg("ds-not-exists","%s数据源不存在",ds));
			}
			return dataSourceService.getDataSource(ds).getConnection();
		} catch (SQLException e) {
			logger.error("db-connection-error",e);
			throw new RuntimeException("db-connection-error",e);
		}
	}


	
	/**获取表的除了主键外的所有字段信息**/
	public void getTableColumnsExcludePkAndNewPk(List<FieldInfo> allColumnsList, List<String> pkList, List<FieldInfo> newPk, List<FieldInfo> columnsExcludePk){
		for (int i = 0; i < allColumnsList.size(); i++) {
			FieldInfo tn=allColumnsList.get(i);
			if(!pkList.contains(tn.getColumnName())){
				columnsExcludePk.add(tn);
				
			}else{
				tn.setPk(true);
				newPk.add(tn);
			}
		}
		
	}
	
	/**获取表的主键名称**/
	public List<String> getPrimaryKeys(String ds,String tableName) {
		ArrayList pklist = new ArrayList();
		Connection conn = getConnection(ds);
		String catalog="";
		String schema="";
		ResultSet primaryKeys = null;
		Map<String,Object> map=new HashMap<String,Object>();
		try {
			catalog=conn.getCatalog();
			schema=conn.getSchema();

			if(dataSourceService==null){
				dataSourceService=SpringContextUtils.getBean(DynamicRoutingDataSource.class);
			}

			if(!dataSourceService.getDataSources().containsKey(ds)){
				catalog=ds;
				schema=ds;
			};
			DatabaseMetaData dmd = conn.getMetaData();
			primaryKeys = dmd.getPrimaryKeys(catalog, schema, tableName.toUpperCase());
			while (primaryKeys.next()) {
				String primaryKey = primaryKeys.getString("COLUMN_NAME").toLowerCase();
			if(map.containsKey(primaryKey)){
					continue;			
			}else{
				pklist.add(primaryKey);
				map.put(primaryKey, primaryKey);
			}
			}
		} catch (SQLException e) {
			throw new RuntimeException(e);
		}  finally {
		}
		if(pklist.size()<=0){
			throw new RuntimeException("没有读取到表对应的主键,请检查表中是否存在主键,如已存在,请检查当前登录用户是否有权限读取.表名:"+tableName+" ,表所属用户:"+schema);
		}
		return pklist;
	}

	/**获取字段中需要在生成的java文件中引入的类名集合**/
	public List<FieldInfo> getImportClass(List<FieldInfo> allColumnsList){
		ArrayList<FieldInfo> importClassList=new ArrayList<FieldInfo>();
		Map<String,FieldInfo> m=new HashMap<String,FieldInfo>();
		for (int i = 0; i < allColumnsList.size(); i++) {
			FieldInfo tn=allColumnsList.get(i);
			if(tn.getFullJavaClassName().contains(".") && !tn.getFullJavaClassName().contains("java.lang") && !m.containsKey(tn.getFullJavaClassName())){
				importClassList.add(tn);
				m.put(tn.getFullJavaClassName(), tn);
			}
		}
		return importClassList;
		
	}

	
	
    
   /**
	*	获取列信息
    */
   public  List<FieldInfo> getColumnsInfo(String ds,String tableName){
   	Connection conn = getConnection();
   	ArrayList<FieldInfo> columnsList = new ArrayList<FieldInfo>();
   	ResultSet rs = null;
   String catalog="";
   String schema="";
   try{
     /**
      * 设置连接属性,使得可获取到列的REMARK(备注)
      
	   if(conn instanceof OracleConnection){
		   ((OracleConnection)conn).setRemarksReporting(true); 
	   }
	   */
	   catalog=conn.getCatalog();
	   schema=conn.getSchema();

	   if(dataSourceService==null){
		   dataSourceService=SpringContextUtils.getBean(DynamicRoutingDataSource.class);
	   }

	   if(!dataSourceService.getDataSources().containsKey(ds)){
		   catalog=ds;
		   schema=ds;
	   };
	  DatabaseMetaData dbmd = conn.getMetaData();
	ResultSet tabrs =dbmd.getTables(catalog, schema,  tableName.toUpperCase(), null);
	String tableRemarks=tableName;
	 while(tabrs.next()){
		 tableRemarks= tabrs.getString("REMARKS");
	 }
	 if(!StringUtils.hasText(tableRemarks)){
		 tableRemarks=tableName;
	 }
     /**
      * 获取可在指定类别中使用的表列的描述。
      * 方法原型:ResultSet getColumns(String catalog,String schemaPattern,String tableNamePattern,String columnNamePattern)
      * catalog - 表所在的类别名称;""表示获取没有类别的列,null表示获取所有类别的列。
      * schema - 表所在的模式名称(oracle中对应于Tablespace);""表示获取没有模式的列,null标识获取所有模式的列; 可包含单字符通配符("_"),或多字符通配符("%");
      * tableNamePattern - 表名称;可包含单字符通配符("_"),或多字符通配符("%");
      * columnNamePattern - 列名称; ""表示获取列名为""的列(当然获取不到);null表示获取所有的列;可包含单字符通配符("_"),或多字符通配符("%");
      */
     rs =dbmd.getColumns(catalog.toUpperCase(), schema.toUpperCase(), tableName.toUpperCase(), null);
     Map<String,Object> map=new HashMap<String,Object>();
     while(rs.next()){
				FieldInfo fieldInfo = new FieldInfo();
				fieldInfo.setTableRemarks(tableRemarks);
				String tableCat = rs.getString("TABLE_CAT"); // 表类别（可能为空）,mysql中为数据库名称
				fieldInfo.setTableSchemaName(rs.getString("TABLE_SCHEM")); // 表模式（可能为空）,在oracle中获取的是命名空间,其它数据库未知
				fieldInfo.setTableName(rs.getString("TABLE_NAME").toLowerCase()); // 表名
				String columnName=rs.getString("COLUMN_NAME").toLowerCase();
				if(map.containsKey(columnName)){
					continue;
				}else{
					map.put(columnName,columnName);
				}
				fieldInfo.setColumnName(columnName); // 列名
				fieldInfo.setDataType(rs.getInt("DATA_TYPE")); // 对应的java.sql.Types的SQL类型(列类型ID)
				fieldInfo.setDataTypeName(rs.getString("TYPE_NAME")); // java.sql.Types类型名称(列类型名称)
				
				fieldInfo.setColumnSize(rs.getInt("COLUMN_SIZE")); // 列大小
				fieldInfo.setDecimalDigits(rs.getInt("DECIMAL_DIGITS")); // 小数位数
				fieldInfo.setNumPrecRadix(rs.getInt("NUM_PREC_RADIX")); // 基数（通常是10或2）
				String dataTypeName=rs.getString("TYPE_NAME");
				String fjcn= JdbcUtils.convertColumnTypeToJavaType(dataTypeName,fieldInfo.getDecimalDigits());
				fieldInfo.setFullJavaClassName(fjcn);
																// --未知
				/**
				 * 0 (columnNoNulls) - 该列不允许为空 1 (columnNullable) - 该列允许为空 2
				 * (columnNullableUnknown) - 不确定该列是否为空
				 */
				fieldInfo.setNullAble(rs.getInt("NULLABLE")); // 是否允许为null
				String remarks=rs.getString("REMARKS");
				if(!StringUtils.hasText(remarks)){
					remarks=columnName;
				}
				fieldInfo.setRemarks(remarks); // 列描述
				fieldInfo.setChinaName(remarks); // 列描述作为中文名字
				fieldInfo.setColumnDef(rs.getString("COLUMN_DEF")); // 默认值
				fieldInfo.setCharOctetLength(rs.getInt("CHAR_OCTET_LENGTH")); // 对于 char
																		// 类型，该长度是列中的最大字节数
				fieldInfo.setOrdinalPosition(rs.getInt("ORDINAL_POSITION")); // 表中列的索引（从1开始）
				/**
				 * ISO规则用来确定某一列的是否可为空(等同于NULLABLE的值:[ 0:'YES'; 1:'NO'; 2:''; ])
				 * YES -- 该列可以有空值; NO -- 该列不能为空; 空字符串--- 不知道该列是否可为空
				 */
				fieldInfo.setIsNullAble(rs.getString("IS_NULLABLE"));

				/**
				 * 指示此列是否是自动递增 YES -- 该列是自动递增的 NO -- 该列不是自动递增 空字串---
				 * 不能确定该列是否自动递增
				 */
				// String isAutoincrement = rs.getString("IS_AUTOINCREMENT");
				// //该参数测试报错
				fieldInfo=genDataDao.createTestData(fieldInfo);
				columnsList.add(fieldInfo);
     }
   }catch(SQLException ex){
	   logger.error("",ex);
   }finally{
   }
   return columnsList;
   }

   /**
    * 
    * @param menuName 菜单中文名字
    * @param url 菜单入口url 如 system/menu/listMenu
    * @param parentid 父菜单菜单编号 生成代码时,一般挂到80 示例代码下
    */
   public String createMenu(String menuid,String menuName,String url,String parentid){
	   Date d=new Date();
	   //insert("insert into cli_menu (menutype,menuid,name,url,parentid,loperate_person,loperate_date) values (?,?,?,?,?,?,?)","A", menuid,menuName,url,parentid,"",d);
	   String sql="insert into cli_menu (menutype,menuid,name,url,parentid,loperate_person,loperate_date) values ('A','"+menuid+"','"+menuName+"','"+url+"','"+parentid+"','"+ DateUtils.format(d, "yyyyMMddHHmmss")+"')";
	   insert(sql);
	   return sql;
   }
   
   public void insert(String sql){
	   Connection conn = getConnection();
	Statement st = null;
	
	try{
		 
		//得到运行环境
		st = conn.createStatement();

		//执行SQL
		 st.executeUpdate(sql);
 
	}catch(Exception ex){
		 logger.error("",ex);
	}finally{
		//释放资源
		if(st != null){
			try {
				st.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}finally{
				st = null;//--> 让他迅速成为java gc的对象
			}
		}
		if(conn != null){
			try {
				conn.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}finally{
				conn = null;//--> 让他迅速成为java gc的对象
			}
		}
	}
   }

	@Override
	public void afterPropertiesSet() throws Exception {

	}
}